package com.kamistoat.meimeistore.modulessystem.service.impl;

import com.kamistoat.meimeistore.apisystem.domain.SysRole;
import com.kamistoat.meimeistore.apisystem.domain.SysUser;
import com.kamistoat.meimeistore.apisystem.entity.*;
import com.kamistoat.meimeistore.commoncore.constant.UserConstants;
import com.kamistoat.meimeistore.commoncore.exception.ServiceException;
import com.kamistoat.meimeistore.commoncore.utils.StringUtils;
import com.kamistoat.meimeistore.commoncore.utils.page.Query;
import com.kamistoat.meimeistore.commonsecurity.utils.SecurityUtils;
import com.kamistoat.meimeistore.commonsecurity.utils.TokenUtils;
import com.kamistoat.meimeistore.modulessystem.dao.SysRoleDao;
import com.kamistoat.meimeistore.modulessystem.service.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kamistoat.meimeistore.commoncore.utils.page.PageUtils;
import org.springframework.transaction.annotation.Transactional;


@Service("sysRoleService")
public class SysRoleServiceImpl extends ServiceImpl<SysRoleDao, SysRoleEntity> implements SysRoleService {

    @Autowired
    SysUserRoleService sysUserRoleService;
    @Autowired
    SysRoleDeptService sysRoleDeptService;
    @Autowired
    SysRoleMenuService sysRoleMenuService;
    @Autowired
    SysUserService sysUserService;
    @Autowired
    TokenUtils tokenUtils;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<SysRoleEntity> page = this.page(
                new Query<SysRoleEntity>().getPage(params),
                new QueryWrapper<SysRoleEntity>()
        );

        return new PageUtils(page);
    }

    /**
     * 根据用户ID查询角色列表.将返回与userId严格对应的角色列表.忽略status
     */
    @Override
    public List<SysRoleEntity> selectRoleList(SysRole sysRole, Long userId) {
        List<SysUserRoleEntity> userRoleEntityList = sysUserRoleService.list(
                new QueryWrapper<SysUserRoleEntity>().eq("user_id", userId));

        // 无任何关联角色
        if (userRoleEntityList == null || userRoleEntityList.size() == 0) {
            return new ArrayList<>();
        }

        // 根据关联找到角色Id
        List<Long> roleIds = userRoleEntityList.stream().map(
                SysUserRoleEntity::getRoleId).collect(Collectors.toList());
        QueryWrapper<SysRoleEntity> queryWrapper = buildBaseWrapper(sysRole);
        return this.list(queryWrapper
                .in("role_id", roleIds)
                .eq("del_flag", UserConstants.ROLE_NORMAL));
    }

    /**
     * 查询全部角色列表，可供管理员使用.忽略status
     */
    @Override
    public List<SysRoleEntity> selectRoleListAll(SysRole sysRole) {
        QueryWrapper<SysRoleEntity> queryWrapper = buildBaseWrapper(sysRole);
        return this.list(queryWrapper.eq("del_flag", UserConstants.ROLE_NORMAL));
    }

    /**
     * 根据userId查询normal状态的角色。
     */
    @Override
    public List<SysRoleEntity> selectRoleListUnderNormal(Long userId) {
        return selectRoleList(new SysRole(), userId).stream()
                .filter(sysRoleEntity -> sysRoleEntity.getStatus().equals(UserConstants.ROLE_NORMAL))
                .collect(Collectors.toList());
    }

    /**
     * 查询当前角色是否拥有超级管理员的角色
     *
     * @param userId
     */
    @Override
    public boolean isAdminWithUserId(Long userId) {
        List<SysRoleEntity> sysRoleEntities = selectRoleListUnderNormal(userId);
        if (sysRoleEntities != null && sysRoleEntities.size() > 0) {
            for (SysRoleEntity sysRoleEntity : sysRoleEntities) {
                if (sysRoleEntity.getRoleName().equals("超级管理员")) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 根据RoleId查询
     */
    @Override
    public SysRoleEntity selectRoleByRoleId(Long roleId) {
        return this.getOne(new QueryWrapper<SysRoleEntity>().eq("role_id", roleId).eq("del_flag", UserConstants.ROLE_NORMAL));
    }

    @Override
    public boolean checkRoleNameUnique(SysRole role) {
        SysRoleEntity one = this.getOne(new QueryWrapper<SysRoleEntity>().eq("role_name", role.getRoleName()));
        return StringUtils.isNotNull(one) && !one.getRoleId().equals(role.getRoleId());
    }

    @Override
    public boolean checkRoleKeyUnique(SysRole role) {
        SysRoleEntity one = this.getOne(new QueryWrapper<SysRoleEntity>().eq("role_key", role.getRoleKey()));
        return StringUtils.isNotNull(one) && !one.getRoleId().equals(role.getRoleId());
    }

    /**
     * 这里只允许修改 Entity的 roleName roleKey menuCheckStrictly deptCheckStrictly
     */
    @Override
    public boolean editExcludeScope(SysRole sysRole) {
        SysRoleEntity sysRoleEntity = new SysRoleEntity();
        BeanUtils.copyProperties(sysRole, sysRoleEntity);
        sysRoleEntity.setRoleSort(null);
        sysRoleEntity.setDataScope(null);
        sysRoleEntity.setStatus(null);
        sysRoleEntity.setDelFlag(null);

        return this.updateById(sysRoleEntity);
    }

    /**
     * 修改 data_scope，关联修改
     */
    @Override
    @Transactional
    public boolean authDataScope(SysRole sysRole) {
        SysRoleEntity sysRoleEntity = new SysRoleEntity();

        // 只更新 RoleEntity 中的 DataScope字段
        sysRoleEntity.setRoleId(sysRole.getRoleId());
        sysRoleEntity.setDataScope(sysRole.getDataScope());
        sysRoleEntity.setUpdateBy(sysRole.getUpdateBy());

        // 更新entity
        boolean updateEntity = this.updateById(sysRoleEntity);
        // 删除旧的关联的 dept 信息
        boolean removeDeptConn = sysRoleDeptService.deleteByRoleId(Arrays.asList(sysRole.getRoleId()));
        // 添加新的 dept 关联信息
        boolean saveDept = saveRoleWithDept(sysRole);

        return updateEntity && removeDeptConn && saveDept;
    }

    /**
     * 关联修改 菜单权限
     */
    @Override
    @Transactional
    public boolean authMenu(SysRole sysRole) {
        // SysRoleEntity 不含菜单权限的内容可以不用修改，只修改 角色和菜单权限的关联关系即可
        // 删除旧的关联 menu 信息
        boolean removeMenuConn = sysRoleMenuService.deleteByRoleId(Arrays.asList(sysRole.getRoleId()));
        // 添加新的 menu 关联信息
        boolean saveMenu = saveRoleWithMenu(sysRole);

        return removeMenuConn && saveMenu;
    }

    /**
     * 不下线更新缓存中的 核心信息令牌
     */
    @Override
    public boolean dealWithCoreLoginUser(SysRole sysRole) {
        // 寻找所有可能被此次修改影响的到的用户
        List<SysUserRoleEntity> roleUserList = sysUserRoleService.list(
                new QueryWrapper<SysUserRoleEntity>().eq("role_id", sysRole.getRoleId()));
        // 将其制作成Ids
        List<Long> userIds = roleUserList.stream().map(SysUserRoleEntity::getUserId).collect(Collectors.toList());
        try {
            // 调用对应服务
            tokenUtils.updateCoreLoginUserCacheOnLine(userIds);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 修改角色状态
     */
    @Override
    public boolean updateRoleStatus(SysRole sysRole) {
        SysRoleEntity sysRoleEntity = new SysRoleEntity();
        sysRoleEntity.setRoleId(sysRole.getRoleId());
        sysRoleEntity.setStatus(sysRole.getStatus());
        sysRoleEntity.setUpdateBy(sysRoleEntity.getUpdateBy());

        return this.updateById(sysRoleEntity);
    }

    /**
     * 删除角色.要求当前角色没有与其他用户绑定。
     * 删除时将角色的权限绑定和部门绑定一并删除
     */
    @Override
    @Transactional
    public boolean deleteRoleByIds(Long[] roleIds) {
        List<SysUserRoleEntity> userBinding = sysUserRoleService.list(new QueryWrapper<SysUserRoleEntity>()
                .in("role_id", Arrays.asList(roleIds))
                .last("LIMIT 1"));
        if (StringUtils.isNotNull(userBinding) && userBinding.size() > 0) {
            throw new ServiceException("id为'" + userBinding.get(0).getRoleId() + "'的角色与id为'" + userBinding.get(0).getUserId() + "'的用户存在绑定关系。请先删除绑定关系");
        }
        // 删除角色和权限的绑定
        boolean roleMenu = sysRoleMenuService.remove(new QueryWrapper<SysRoleMenuEntity>().in("role_id", Arrays.asList(roleIds)));
        boolean roleDept = sysRoleDeptService.remove(new QueryWrapper<SysRoleDeptEntity>().in("role_id", Arrays.asList(roleIds)));
        boolean removeByIds = this.removeByIds(Arrays.asList(roleIds));
        return roleMenu && roleDept && removeByIds;
    }

    /**
     * 批量绑定用户授权
     */
    @Override
    @Transactional
    public boolean insertAuthUsers(Long roleId, Long[] userIds) {
        List<SysUserRoleEntity> insertBatch = Arrays.stream(userIds).map(userId -> {
            SysUserRoleEntity one = new SysUserRoleEntity();
            one.setRoleId(roleId);
            one.setUserId(userId);
            return one;
        }).collect(Collectors.toList());
        return sysUserRoleService.saveBatch(insertBatch);
    }

    /**
     * 批量取消授权用户
     */
    @Override
    @Transactional
    public boolean deleteAuthUsers(Long roleId, Long[] userIds) {
        try {
            for (Long userId : userIds) {
                sysUserRoleService.remove(new QueryWrapper<SysUserRoleEntity>()
                        .eq("user_id", userId)
                        .eq("role_id", roleId));
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 查询 roleId 下的授权用户列表
     * 返回结果受到 当前用户数据权限的限制
     */
    @Override
    public List<SysUserEntity> selectAllocatedUserList(SysUser sysUser) {
        Long targetRoleId = sysUser.getRoleId();
        // 未经筛选的目标roleId的所有授权用户ids
        List<Long> allRoleUserIds = sysUserRoleService.list(new QueryWrapper<SysUserRoleEntity>().eq("role_id", targetRoleId))
                .stream().map(SysUserRoleEntity::getUserId)
                .collect(Collectors.toList());

        return selectConditionalRoleUser(sysUser, allRoleUserIds);
    }

    /**
     * 查询 roleId 下的未经授权用户列表
     * 返回结果受到 当前用户数据权限的限制
     */
    @Override
    public List<SysUserEntity> selectUnAllocatedUserList(SysUser sysUser) {
        Long targetRoleId = sysUser.getRoleId();
        // 未经筛选的目标roleId的所有未经授权用户ids
        List<Long> allUnRoleUserIds = sysUserRoleService.list(new QueryWrapper<SysUserRoleEntity>().ne("role_id", targetRoleId))
                .stream().map(SysUserRoleEntity::getUserId)
                .collect(Collectors.toList());

        return selectConditionalRoleUser(sysUser, allUnRoleUserIds);
    }

    private List<SysUserEntity> selectConditionalRoleUser(SysUser sysUser, List<Long> roleUserIds) {
        QueryWrapper<SysUserEntity> queryWrapper = new QueryWrapper<>();

        // 设置数据权限
        queryWrapper.in("user_id", roleUserIds);
        queryWrapper.in("dept_id", SecurityUtils.getLoginUser().getAllowedDeptIds());

        // 同时承担条件查询功能
        if (StringUtils.isNotNull(sysUser.getUserName())) {
            queryWrapper.eq("user_name", sysUser.getUserName());
        }
        if (StringUtils.isNotNull(sysUser.getPhonenumber())) {
            queryWrapper.eq("phonenumber", sysUser.getPhonenumber());
        }

        return sysUserService.list(queryWrapper);
    }


    /**
     * 添加新的角色-部门关联信息
     */
    private boolean saveRoleWithDept(SysRole sysRole) {
        List<SysRoleDeptEntity> saveList = Arrays.stream(sysRole.getDeptIds()).map(deptId -> {
            SysRoleDeptEntity one = new SysRoleDeptEntity();
            one.setRoleId(sysRole.getRoleId());
            one.setDeptId(deptId);
            return one;
        }).collect(Collectors.toList());
        return sysRoleDeptService.saveBatch(saveList);
    }

    /**
     * 添加新的 橘色-权限 关联信息
     */
    private boolean saveRoleWithMenu(SysRole sysRole) {
        List<SysRoleMenuEntity> saveList = Arrays.stream(sysRole.getMenuIds()).map(menuId -> {
            SysRoleMenuEntity one = new SysRoleMenuEntity();
            one.setRoleId(sysRole.getRoleId());
            one.setMenuId(menuId);
            return one;
        }).collect(Collectors.toList());
        return sysRoleMenuService.saveBatch(saveList);
    }

    private QueryWrapper<SysRoleEntity> buildBaseWrapper(SysRole sysRole) {
        QueryWrapper<SysRoleEntity> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isNotNull(sysRole.getRoleId())) {
            queryWrapper.eq("role_id", sysRole.getRoleId());
        }
        if (StringUtils.isNotNull(sysRole.getRoleName())) {
            queryWrapper.eq("role_name", sysRole.getRoleName());
        }
        if (StringUtils.isNotNull(sysRole.getRoleKey())) {
            queryWrapper.like("role_key", sysRole.getRoleKey());
        }
        if (StringUtils.isNotNull(sysRole.getStatus())) {
            queryWrapper.eq("status", sysRole.getStatus());
        } else {
            queryWrapper.eq("status", UserConstants.ROLE_NORMAL);
        }
        return queryWrapper;
    }

}